/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the EternalTech source code.

 The EternalTech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The EternalTech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the EternalTech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// r_framebuffer.cpp - ...
//


#include "r_local.h"


static framebuffer_t *		r_framebuffers[MAX_FRAMEBUFFERS];
static int					r_numFramebuffers;


/*
 ==================
 R_CreateFramebuffer
 ==================
*/
framebuffer_t *R_CreateFramebuffer (const char *name, int width, int height, int depth){

	framebuffer_t	*framebuffer;

	if (r_numFramebuffers == MAX_FRAMEBUFFERS)
		Com_Error(false, "R_CreateFramebuffer: MAX_FRAMEBUFFERS hit");

	r_framebuffers[r_numFramebuffers++] = framebuffer = (framebuffer_t *)Mem_Alloc(sizeof(framebuffer_t), TAG_RENDERER);

	// Fill it in
	Str_Copy(framebuffer->name, name, sizeof(framebuffer->name));
	framebuffer->width = width;
	framebuffer->height = height;
	framebuffer->depth = depth;

	// Set framebuffer rectangle
	framebuffer->rect.Set(0, 0, width, height);

	// Clear the textures
	framebuffer->colorTexture = NULL;
	framebuffer->depthTexture = NULL;

	// Clear the buffers
	Mem_Fill(&framebuffer->colorBuffer, 0, sizeof(renderbuffer_t));
	Mem_Fill(&framebuffer->depthBuffer, 0, sizeof(renderbuffer_t));
	Mem_Fill(&framebuffer->stencilBuffer, 0, sizeof(renderbuffer_t));

	// Generate the framebuffer
	qglGenFramebuffers(1, &framebuffer->framebufferId);

	return framebuffer;
}

/*
 ==================
 R_ResizeFramebuffer
 ==================
*/
void R_ResizeFramebuffer (framebuffer_t *framebuffer, int width, int height, int depth){

	// Fill it in
	framebuffer->width = width;
	framebuffer->height = height;
	framebuffer->depth = depth;

	// Set framebuffer rectangle
	framebuffer->rect.Set(0, 0, width, height);
}

/*
 ==================
 R_AttachColorTextureToFramebuffer
 ==================
*/
void R_AttachColorTextureToFramebuffer (framebuffer_t *framebuffer, texture_t *texture, int index, int colorIndex){

	// If a 2D texture
	if (texture->type == TT_2D){
		// Set the texture
		framebuffer->colorTexture = texture;

		// If the framebuffer has been resized
		if (texture->width != framebuffer->width || texture->height != framebuffer->height){
			// Check the dimensions
			if (framebuffer->width > glConfig.maxTextureSize || framebuffer->height > glConfig.maxTextureSize)
				Com_Error(false, "R_AttachColorTextureToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxTextureSize, framebuffer->height, glConfig.maxTextureSize);

			// Reallocate the texture
			texture->width = framebuffer->width;
			texture->height = framebuffer->height;
			texture->frameUsed = 0;

			R_SetTextureSize(texture);

			GL_BindTexture(texture);

			qglTexImage2D(GL_TEXTURE_2D, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		}

		// Bind the framebuffer
		GL_BindFramebuffer(framebuffer);

		// Set up the color attachment
		qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, GL_TEXTURE_2D, texture->textureId, 0);

		return;
	}

	// If a cube texture
	if (texture->type == TT_CUBE){
		// Set the texture
		framebuffer->colorTexture = texture;

		// If the framebuffer has been resized
		if (texture->width != framebuffer->width || texture->height != framebuffer->height){
			// Check the dimensions
			if (framebuffer->width > glConfig.maxCubeMapTextureSize || framebuffer->height > glConfig.maxCubeMapTextureSize)
				Com_Error(false, "R_AttachColorTextureToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxCubeMapTextureSize, framebuffer->height, glConfig.maxCubeMapTextureSize);

			// Reallocate the texture
			texture->width = framebuffer->width;
			texture->height = framebuffer->height;
			texture->frameUsed = 0;

			R_SetTextureSize(texture);

			GL_BindTexture(texture);

			qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, texture->internalFormat, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		}

		// Bind the framebuffer
		GL_BindFramebuffer(framebuffer);

		// Set up the color attachment
		qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, texture->textureId, 0);

		return;
	}

	// If an array texture
	if (texture->type == TT_ARRAY){
		// Set the texture
		framebuffer->colorTexture = texture;

		// If the framebuffer has been resized
		if (texture->width != framebuffer->width || texture->height != framebuffer->height || texture->depth != framebuffer->depth){
			// Check the dimensions
			if (framebuffer->width > glConfig.maxTextureSize || framebuffer->height > glConfig.maxTextureSize || framebuffer->depth > glConfig.maxArrayTextureLayers)
				Com_Error(false, "R_AttachColorTextureToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i or %i > %i)", framebuffer->width, glConfig.maxTextureSize, framebuffer->height, glConfig.maxTextureSize, framebuffer->depth, glConfig.maxArrayTextureLayers);

			// Reallocate the texture
			texture->width = framebuffer->width;
			texture->height = framebuffer->height;
			texture->depth = framebuffer->depth;
			texture->frameUsed = 0;

			R_SetTextureSize(texture);

			GL_BindTexture(texture);

			qglTexImage3D(GL_TEXTURE_2D_ARRAY, 0, texture->internalFormat, texture->width, texture->height, texture->depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		}

		// Bind the framebuffer
		GL_BindFramebuffer(framebuffer);

		// Set up the color attachment
		qglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, texture->textureId, 0, index);

		return;
	}

	Com_Error(false, "R_AttachColorTextureToFramebuffer: bad texture type (%i)", texture->type);
}

/*
 ==================
 R_AttachDepthTextureToFramebuffer
 ==================
*/
void R_AttachDepthTextureToFramebuffer (framebuffer_t *framebuffer, texture_t *texture, int index){

	// If a 2D texture
	if (texture->type == TT_2D){
		// Set the texture
		framebuffer->depthTexture = texture;

		// If the framebuffer has been resized
		if (texture->width != framebuffer->width || texture->height != framebuffer->height){
			// Check the dimensions
			if (framebuffer->width > glConfig.maxTextureSize || framebuffer->height > glConfig.maxTextureSize)
				Com_Error(false, "R_AttachDepthTextureToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxTextureSize, framebuffer->height, glConfig.maxTextureSize);

			// Reallocate the texture
			texture->width = framebuffer->width;
			texture->height = framebuffer->height;
			texture->frameUsed = 0;

			R_SetTextureSize(texture);

			GL_BindTexture(texture);

			qglTexImage2D(GL_TEXTURE_2D, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
		}

		// Bind the framebuffer
		GL_BindFramebuffer(framebuffer);

		// Set up the depth attachment
		qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture->textureId, 0);

		return;
	}

	// If a cube texture
	if (texture->type == TT_CUBE){
		// Set the texture
		framebuffer->depthTexture = texture;

		// If the framebuffer has been resized
		if (texture->width != framebuffer->width || texture->height != framebuffer->height){
			// Check the dimensions
			if (framebuffer->width > glConfig.maxCubeMapTextureSize || framebuffer->height > glConfig.maxCubeMapTextureSize)
				Com_Error(false, "R_AttachDepthTextureToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxCubeMapTextureSize, framebuffer->height, glConfig.maxCubeMapTextureSize);

			// Reallocate the texture
			texture->width = framebuffer->width;
			texture->height = framebuffer->height;
			texture->frameUsed = 0;

			R_SetTextureSize(texture);

			GL_BindTexture(texture);

			qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
			qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, texture->internalFormat, texture->width, texture->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
		}

		// Bind the framebuffer
		GL_BindFramebuffer(framebuffer);

		// Set up the depth attachment
		qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, texture->textureId, 0);

		return;
	}

	// If an array texture
	if (texture->type == TT_ARRAY){
		// Set the texture
		framebuffer->depthTexture = texture;

		// If the framebuffer has been resized
		if (texture->width != framebuffer->width || texture->height != framebuffer->height || texture->depth != framebuffer->depth){
			// Check the dimensions
			if (framebuffer->width > glConfig.maxTextureSize || framebuffer->height > glConfig.maxTextureSize || framebuffer->depth > glConfig.maxArrayTextureLayers)
				Com_Error(false, "R_AttachDepthTextureToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i or %i > %i)", framebuffer->width, glConfig.maxTextureSize, framebuffer->height, glConfig.maxTextureSize, framebuffer->depth, glConfig.maxArrayTextureLayers);

			// Reallocate the texture
			texture->width = framebuffer->width;
			texture->height = framebuffer->height;
			texture->depth = framebuffer->depth;
			texture->frameUsed = 0;

			R_SetTextureSize(texture);

			GL_BindTexture(texture);

			qglTexImage3D(GL_TEXTURE_2D_ARRAY, 0, texture->internalFormat, texture->width, texture->height, texture->depth, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
		}

		// Bind the framebuffer
		GL_BindFramebuffer(framebuffer);

		// Set up the depth attachment
		qglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture->textureId, 0, index);

		return;
	}

	Com_Error(false, "R_AttachDepthTextureToFramebuffer: bad texture type (%i)", texture->type);
}

/*
 ==================
 R_AttachColorBufferToFramebuffer
 ==================
*/
void R_AttachColorBufferToFramebuffer (framebuffer_t *framebuffer, uint format, int colorIndex){

	renderbuffer_t	*colorBuffer = &framebuffer->colorBuffer;

	// If the format changed or the framebuffer has been resized
	if (format != colorBuffer->format || framebuffer->width != colorBuffer->width || framebuffer->height != colorBuffer->height){
		// Check the dimensions
		if (framebuffer->width > glConfig.maxRenderbufferSize || framebuffer->height > glConfig.maxRenderbufferSize)
			Com_Error(false, "R_AttachColorBufferToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxRenderbufferSize, framebuffer->height, glConfig.maxRenderbufferSize);

		// Reallocate the buffer
		colorBuffer->width = framebuffer->width;
		colorBuffer->height = framebuffer->height;
		colorBuffer->format = format;

		switch (format){
		case GL_R8:
			colorBuffer->size = framebuffer->width * framebuffer->height;
			break;
		case GL_RG8:
			colorBuffer->size = framebuffer->width * framebuffer->height * 2;
			break;
		case GL_RGB8:
			colorBuffer->size = framebuffer->width * framebuffer->height * 4;
			break;
		case GL_RGBA8:
			colorBuffer->size = framebuffer->width * framebuffer->height * 4;
			break;
		default:
			Com_Error(false, "R_AttachColorBufferToFramebuffer: bad buffer format (%u)", format);
		}

		if (colorBuffer->renderbufferId)
			qglBindRenderbuffer(GL_RENDERBUFFER, colorBuffer->renderbufferId);
		else {
			qglGenRenderbuffers(1, &colorBuffer->renderbufferId);
			qglBindRenderbuffer(GL_RENDERBUFFER, colorBuffer->renderbufferId);
		}

		qglRenderbufferStorage(GL_RENDERBUFFER, colorBuffer->format, colorBuffer->width, colorBuffer->height);
	}

	// Bind the framebuffer
	GL_BindFramebuffer(framebuffer);

	// Set up the color attachment
	qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorIndex, GL_RENDERBUFFER, colorBuffer->renderbufferId);
}

/*
 ==================
 R_AttachDepthBufferToFramebuffer
 ==================
*/
void R_AttachDepthBufferToFramebuffer (framebuffer_t *framebuffer, uint format){

	renderbuffer_t	*depthBuffer = &framebuffer->depthBuffer;

	// If the format changed or the framebuffer has been resized
	if (format != depthBuffer->format || framebuffer->width != depthBuffer->width || framebuffer->height != depthBuffer->height){
		// Check the dimensions
		if (framebuffer->width > glConfig.maxRenderbufferSize || framebuffer->height > glConfig.maxRenderbufferSize)
			Com_Error(false, "R_AttachDepthBufferToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxRenderbufferSize, framebuffer->height, glConfig.maxRenderbufferSize);

		// Reallocate the buffer
		depthBuffer->width = framebuffer->width;
		depthBuffer->height = framebuffer->height;
		depthBuffer->format = format;

		switch (format){
		case GL_DEPTH_COMPONENT16:
			depthBuffer->size = framebuffer->width * framebuffer->height * 2;
			break;
		case GL_DEPTH_COMPONENT24:
			depthBuffer->size = framebuffer->width * framebuffer->height * 4;
			break;
		case GL_DEPTH24_STENCIL8:
			depthBuffer->size = framebuffer->width * framebuffer->height * 4;
			break;
		default:
			Com_Error(false, "R_AttachDepthBufferToFramebuffer: bad buffer format (%u)", format);
		}

		if (depthBuffer->renderbufferId)
			qglBindRenderbuffer(GL_RENDERBUFFER, depthBuffer->renderbufferId);
		else {
			qglGenRenderbuffers(1, &depthBuffer->renderbufferId);
			qglBindRenderbuffer(GL_RENDERBUFFER, depthBuffer->renderbufferId);
		}

		qglRenderbufferStorage(GL_RENDERBUFFER, depthBuffer->format, depthBuffer->width, depthBuffer->height);
	}

	// Bind the framebuffer
	GL_BindFramebuffer(framebuffer);

	// Set up the depth attachment
	qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer->renderbufferId);

	// Set up the stencil attachment if needed
	if (depthBuffer->format != GL_DEPTH24_STENCIL8)
		return;

	qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthBuffer->renderbufferId);
}

/*
 ==================
 R_AttachStencilBufferToFramebuffer
 ==================
*/
void R_AttachStencilBufferToFramebuffer (framebuffer_t *framebuffer, uint format){

	renderbuffer_t	*stencilBuffer = &framebuffer->stencilBuffer;

	// If the format changed or the framebuffer has been resized
	if (format != stencilBuffer->format || framebuffer->width != stencilBuffer->width || framebuffer->height != stencilBuffer->height){
		// Check the dimensions
		if (framebuffer->width > glConfig.maxRenderbufferSize || framebuffer->height > glConfig.maxRenderbufferSize)
			Com_Error(false, "R_AttachStencilBufferToFramebuffer: size exceeds hardware limits (%i > %i or %i > %i)", framebuffer->width, glConfig.maxRenderbufferSize, framebuffer->height, glConfig.maxRenderbufferSize);

		// Reallocate the buffer
		stencilBuffer->width = framebuffer->width;
		stencilBuffer->height = framebuffer->height;
		stencilBuffer->format = format;

		switch (format){
		case GL_STENCIL_INDEX8:
			stencilBuffer->size = framebuffer->width * framebuffer->height;
			break;
		default:
			Com_Error(false, "R_AttachStencilBufferToFramebuffer: bad buffer format (%u)", format);
		}

		if (stencilBuffer->renderbufferId)
			qglBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer->renderbufferId);
		else {
			qglGenRenderbuffers(1, &stencilBuffer->renderbufferId);
			qglBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer->renderbufferId);
		}

		qglRenderbufferStorage(GL_RENDERBUFFER, stencilBuffer->format, stencilBuffer->width, stencilBuffer->height);
	}

	// Bind the framebuffer
	GL_BindFramebuffer(framebuffer);

	// Set up the stencil attachment
	qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilBuffer->renderbufferId);
}

/*
 ==================
 R_CheckFramebufferStatus
 ==================
*/
void R_CheckFramebufferStatus (framebuffer_t *framebuffer){

	const char	*string;
	int			status;

	// Bind the framebuffer
	GL_BindFramebuffer(framebuffer);

	// Check the framebuffer status
	status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);

	if (status == GL_FRAMEBUFFER_COMPLETE)
		return;

	switch (status){
	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
		string = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
		string = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
		string = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
		string = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
		string = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
		break;
	case GL_FRAMEBUFFER_UNSUPPORTED:
		string = "GL_FRAMEBUFFER_UNSUPPORTED";
		break;
	case GL_FRAMEBUFFER_UNDEFINED:
		string = "GL_FRAMEBUFFER_UNDEFINED";
		break;
	default:
		string = "UNKNOWN STATUS";
		break;
	}

	Com_Error(false, "R_CheckFramebufferStatus: %s for '%s'", string, framebuffer->name);
}


/*
 ==============================================================================

 CONSOLE COMMANDS

 ==============================================================================
*/


/*
 ==================
 R_ListFramebuffers_f
 ==================
*/
static void R_ListFramebuffers_f (){

	framebuffer_t	*framebuffer;
	int				size, bytes = 0;
	int				i;
		
	Com_Printf("\n");
	Com_Printf("      -w-- -h-- -d-- -size- -name-----------\n");

	for (i = 0; i < r_numFramebuffers; i++){
		framebuffer = r_framebuffers[i];

		size = 0;

		if (framebuffer->colorTexture)
			size += framebuffer->colorTexture->size;
		if (framebuffer->depthTexture)
			size += framebuffer->depthTexture->size;

		size += framebuffer->colorBuffer.size;
		size += framebuffer->depthBuffer.size;
		size += framebuffer->stencilBuffer.size;

		bytes += size;

		Com_Printf("%4i: ", i);

		Com_Printf("%4i %4i %4i ", framebuffer->width, framebuffer->height, framebuffer->depth);

		Com_Printf("%5ik ", SIZE_KB(size));

		Com_Printf("%s\n", framebuffer->name);
	}

	Com_Printf("--------------------------------------------\n");
	Com_Printf("%i total framebuffers\n", r_numFramebuffers);
	Com_Printf("%.2f MB of framebuffer data\n", SIZE_MB_FLOAT(bytes));
	Com_Printf("\n");
}


/*
 ==============================================================================

 INITIALIZATION & SHUTDOWN

 ==============================================================================
*/


/*
 ==================
 R_InitFramebuffers
 ==================
*/
void R_InitFramebuffers (){

	// Add commands
	Cmd_AddCommand("listFramebuffers", R_ListFramebuffers_f, "Lists framebuffers", NULL);
}

/*
 ==================
 R_ShutdownFramebuffers
 ==================
*/
void R_ShutdownFramebuffers (){

	framebuffer_t	*framebuffer;
	int				i;

	// Remove commands
	Cmd_RemoveCommand("listFramebuffers");

	// Delete all the framebuffers
	qglBindFramebuffer(GL_FRAMEBUFFER, 0);

	for (i = 0; i < r_numFramebuffers; i++){
		framebuffer = r_framebuffers[i];

		if (framebuffer->colorBuffer.renderbufferId)
			qglDeleteRenderbuffers(1, &framebuffer->colorBuffer.renderbufferId);
		if (framebuffer->depthBuffer.renderbufferId)
			qglDeleteRenderbuffers(1, &framebuffer->depthBuffer.renderbufferId);
		if (framebuffer->stencilBuffer.renderbufferId)
			qglDeleteRenderbuffers(1, &framebuffer->stencilBuffer.renderbufferId);

		qglDeleteFramebuffers(1, &framebuffer->framebufferId);
	}

	// Clear framebuffer list
	Mem_Fill(r_framebuffers, 0, sizeof(r_framebuffers));

	r_numFramebuffers = 0;
}